<template>
  <view class="waterfalls-flow">
    <view v-for="(item,index) in data.column" :key="index" class="waterfalls-flow-column"
      :id="`waterfalls_flow_column_${index+1}`" :msg="msg" :style="{'width':w,'margin-left':index==0?0:m}">
      <view :class="['column-value',{'column-value-show':item2.o}]" v-for="(item2,index2) in columnValue(index)"
        :key="index2" :style="[s1]" @click.stop="wapperClick(item2)">
        <view class="inner" v-if="data.seat==1">
          <!-- #ifdef MP-WEIXIN -->
          <!-- #ifdef VUE2 -->
          <slot name="slot{{item2.index}}"></slot>
          <!-- #endif -->
          <!-- #ifdef VUE3 -->
          <slot :name="`slot${item2.index}`"></slot>
          <!-- #endif -->
          <!-- #endif -->
          <!-- #ifndef MP-WEIXIN -->
          <slot v-bind="item2"></slot>
          <!-- #endif -->
        </view>
        <image
          :class="['img',{'img-hide':item2[hideImageKey]==true||item2[hideImageKey]==1},{'img-error':!item2[data.imageKey]}]"
          :style="{
            'max-height':imgMaxHeight }" :src="item2[data.imageKey]" mode="widthFix" @load="imgLoad(item2,index+1)"
          @error="imgError(item2,index+1)" @click.stop="imageClick(item2)"></image>
        <view class="inner" v-if="data.seat==2">
          <!-- #ifdef MP-WEIXIN -->
          <!-- #ifdef VUE2 -->
          <slot name="slot{{item2.index}}"></slot>
          <!-- #endif -->
          <!-- #ifdef VUE3 -->
          <slot :name="`slot${item2.index}`"></slot>
          <!-- #endif -->
          <!-- #endif -->
          <!-- #ifndef MP-WEIXIN -->
          <slot v-bind="item2"></slot>
          <!-- #endif -->
        </view>
      </view>
    </view>
  </view>
</template>
<script>
  export default {
    props: {
      value: Array,
      column: { // 列的数量 
        type: [String, Number],
        default: 2
      },
      maxColumn: { // 最大列数 
        type: [String, Number],
        default: 5
      },
      columnSpace: { // 列之间的间距 百分比
        type: [String, Number],
        default: 2
      },
      imageKey: { // 图片key
        type: [String],
        default: 'image'
      },
      hideImageKey: { // 隐藏图片key
        type: [String],
        default: 'hide'
      },
      seat: { // 文本的位置，1图片之上 2图片之下
        type: [String, Number],
        default: 2
      },
      listStyle: { // 单个展示项的样式：eg:{'background':'red'}
        type: Object
      },
      imgMaxHeight: {
        type: String,
        default: 'auto'
      }
    },
    data() {
      return {
        data: {
          list: this.value ? this.value : [],
          column: this.column < 2 ? 2 : this.column,
          columnSpace: this.columnSpace <= 5 ? this.columnSpace : 5,
          imageKey: this.imageKey,
          seat: this.seat
        },
        msg: 0,
        listInitStyle: {
          'border-radius': '12rpx',
          'margin-bottom': '20rpx',
          'background-color': '#fff'
        },
        adds: [], //预置数据
        isLoaded: true,
        curIndex: 0,
        isRefresh: true,
        flag: false,
        refreshDatas: []
      }
    },
    computed: {
      // 计算列宽
      w() {
        const column_rate = `${100 / this.data.column - (+this.data.columnSpace)}%`;
        return column_rate;
      },
      // 计算margin
      m() {
        const column_margin =
          `${(100-(100 / this.data.column - (+this.data.columnSpace)).toFixed(5)*this.data.column)/(this.data.column-1)}%`;
        return column_margin;
      },
      // list样式
      s1() {
        return {
          ...this.listInitStyle,
          ...this.listStyle
        };
      }
    },
    created() {
      // 初始化
      this.refresh();
    },
    methods: {
      // 预加载图片
      loadImages(idx = 0) {
        let count = 0;
        const newList = this.data.list.filter((item, index) => index >= idx);
        for (let i = 0; i < newList.length; i++) {
          // #ifndef APP-PLUS
          uni.getImageInfo({
            src: `${newList[i][this.imageKey]}.jpg`,
            complete: res => {
              count++;
              if (count == newList.length) this.initValue(idx);
            }
          })
          // #endif
          // #ifdef APP-PLUS
          plus.io.getImageInfo({
            src: `${newList[i][this.imageKey]}.jpg`,
            complete: res => {
              count++;
              if (count == newList.length) this.initValue(idx);
            }
          })
          // #endif
        }
      },
      // 刷新
      refresh() {
        if (!this.isLoaded) {
          this.refreshDatas = this.value;
          return false;
        };
        setTimeout(() => {
          this.refreshDatas = [];
          this.isRefresh = true;
          this.adds = [];
          this.data.list = this.value ? this.value : [];
          this.data.column = this.column < 2 ? 2 : this.column >= this.maxColumn ? this.maxColumn : this.column;
          this.data.columnSpace = this.columnSpace <= 5 ? this.columnSpace : 5;
          this.data.imageKey = this.imageKey;
          this.data.seat = this.seat;
          this.curIndex = 0;
          // 每列的数据初始化
          for (let i = 1; i <= this.data.column; i++) {
            this.data[`column_${i}_values`] = [];
            this.msg++;
          }
          this.$nextTick(() => {
            this.initValue(this.curIndex, 'refresh==>');
          })
        }, 1)
      },
      columnValue(index) {
        return this.data[`column_${index+1}_values`];
      },
      change(newValue) {
        for (let i = 0; i < this.data.list.length; i++) {
          const cv = this.data[`column_${this.data.list[i].column}_values`];
          for (let j = 0; j < cv.length; j++) {
            if (newValue[i] && i === cv[j].index) {
              this.data[`column_${this.data.list[i].column}_values`][j] = Object.assign(cv[j], newValue[i]);
              this.msg++;
              break;
            }
          }
        }
      },
      getMin(a, s) {
        let m = a[0][s];
        let mo = a[0];
        for (var i = a.length - 1; i >= 0; i--) {
          if (a[i][s] < m) {
            m = a[i][s];
          }
        }
        mo = a.filter(i => i[s] == m);
        return mo[0];
      },
      // 计算每列的高度
      getMinColumnHeight() {
        return new Promise(resolve => {
          const heightArr = [];
          for (let i = 1; i <= this.data.column; i++) {
            const query = uni.createSelectorQuery().in(this);
            query.select(`#waterfalls_flow_column_${i}`).boundingClientRect(data => {
              heightArr.push({
                column: i,
                height: data.height
              });
            }).exec(() => {
              if (this.data.column <= heightArr.length) {
                resolve(this.getMin(heightArr, 'height'));
              }
            });
          }
        })
      },
      async initValue(i, from) {
        this.isLoaded = false;
        if (i >= this.data.list.length || this.refreshDatas.length) {
          this.msg++;
          this.loaded();
          return false;
        }
        const minHeightRes = await this.getMinColumnHeight();
        const c = this.data[`column_${minHeightRes.column}_values`];
        this.data.list[i].column = minHeightRes.column;
        c.push({
          ...this.data.list[i],
          cIndex: c.length,
          index: i,
          o: 0
        });
        this.msg++;
      },
      // 图片加载完成
      imgLoad(item, c) {
        const i = item.index;
        item.o = 1;
        this.$set(this.data[`column_${c}_values`], item.cIndex, JSON.parse(JSON.stringify(item)));
        this.initValue(i + 1);
      },
      // 图片加载失败
      imgError(item, c) {
        const i = item.index;
        item.o = 1;
        item[this.data.imageKey] = null;
        this.$set(this.data[`column_${c}_values`], item.cIndex, JSON.parse(JSON.stringify(item)));
        this.initValue(i + 1);
      },
      // 渲染结束
      loaded() {
        if (this.refreshDatas.length) {
          this.isLoaded = true;
          this.refresh();
          return false;
        }
        this.curIndex = this.data.list.length;
        if (this.adds.length) {
          this.data.list = this.adds[0];
          this.adds.splice(0, 1);
          this.initValue(this.curIndex);
        } else {
          if (this.data.list.length) this.$emit('loaded');
          this.isLoaded = true;
          this.isRefresh = false;
        }
      },
      // 单项点击事件
      wapperClick(item) {
        this.$emit('wapperClick', item);
      },
      // 图片点击事件
      imageClick(item) {
        this.$emit('imageClick', item);
      }
    },
    watch: {
      value: {
        deep: true,
        handler(newValue, oldValue) {
          setTimeout(() => {
            this.$nextTick(() => {
              if (this.isRefresh) return false;
              if (this.isLoaded) {
                // if (newValue.length <= this.curIndex) return this.refresh();
                if (newValue.length <= this.curIndex) return this.change(newValue);
                this.data.list = newValue;
                this.$nextTick(() => {
                  this.initValue(this.curIndex, 'watch==>');
                })
              } else {
                this.adds.push(newValue);
              }
            })
          }, 10)
        }
      },
      column(newValue) {
        this.refresh();
      }
    }
  }
</script>
<style lang="scss" scoped>
  .waterfalls-flow {
    overflow: hidden;

    &-column {
      float: left;
    }
  }

  .column-value {
    width: 100%;
    font-size: 0;
    overflow: hidden;
    transition: opacity .4s;
    opacity: 0;

    &-show {
      opacity: 1;
    }

    .inner {
      font-size: 30rpx;
    }

    .img {
      width: 100%;

      &-hide {
        display: none;
      }

      &-error {
        background: #f2f2f2 url() no-repeat center center;
      }
    }
  }
</style>